package model

import (
	"errors"
	"fmt"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/cache"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/hashid"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/util"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"math"
	"strings"
	"time"
)

// ItemService 处理多文件/目录相关服务
type FolderItem struct {
	Folder Folder `json:"folder"`
	Dir    uint   `json:"dir"`
}

// Share 分享模型
type TeamsFolderMember struct {
	ID              uint `gorm:"primary_key"`
	CreatedAt       time.Time
	UpdatedAt       time.Time
	Password        string     // 分享密码，空值为非加密分享
	IsDir           bool       // 原始资源是否为目录
	UserID          uint       // 创建用户ID
	SourceID        uint       // 原始资源ID
	Views           int        // 浏览数
	Downloads       int        // 下载数
	RemainDownloads int        // 剩余下载配额，负值标识无限制
	Expires         *time.Time // 过期时间，空值表示无过期时间
	Score           int        // 每人次下载扣除积分
	GroupRole       int        // 角色
	PreviewEnabled  bool       // 是否允许直接预览
	SourceName      string     `gorm:"index:source"` // 用于搜索的字段
	DownloadEnabled bool       // 是否允许直接下载
	UploadEnabled   bool       // 是否允许直接上传
	EditEnabled     bool       // 是否允许直接编辑
	ManaEnabled     bool       // 是否允许直接管理
	IsRoot          bool       // 是否根节点
	// 数据库忽略字段
	User   User   `gorm:"PRELOAD:false,association_autoupdate:false"`
	File   File   `gorm:"PRELOAD:false,association_autoupdate:false"`
	Folder Folder `gorm:"PRELOAD:false,association_autoupdate:false"`
}

// Create 创建分享
func (share *TeamsFolderMember) Create() (uint, error) {
	if err := DB.Create(share).Error; err != nil {
		util.Log().Warning("无法插入数据库记录, %s", err)
		return 0, err
	}
	return share.ID, nil
}
func GetUserTeamsRootFolder(userId uint) (sourceIds []uint) {
	DB.Model(TeamsFolderMember{}).Where("user_id = ? and  is_root = 1 ", userId).Pluck("source_id", &sourceIds)
	return sourceIds
}
func GetUserTeamsFolder(userId uint, sourceId uint) (source TeamsFolderMember) {
	DB.Model(TeamsFolderMember{}).Where("user_id = ? and  source_id = ? ", userId, sourceId).First(&source)
	return source
}

// ListShares 列出UID下的分享
func ListTeamsShare(uid uint, publicOnly bool) ([]TeamsFolderMember, error) {
	var (
		shares []TeamsFolderMember
	)
	dbChain := DB
	dbChain = dbChain.Where("user_id = ? and is_root= 1", uid)
	if publicOnly {
		dbChain = dbChain.Where("password = ?", "")
	}

	// 计算总数用于分页
	//dbChain.Model(&Share{}).Count(&total)

	// 查询记录
	dbChain.Find(&shares)
	return shares, nil
}
func ListTeamsGroupFolder(folder_id uint, key string) ([]TeamsFolderMember, error) {
	var (
		shares []TeamsFolderMember
	)
	dbChain := DB
	dbChain = dbChain.Where("source_id = ?", folder_id)

	// 计算总数用于分页
	//dbChain.Model(&Share{}).Count(&total)

	// 查询记录
	dbChain.Find(&shares)

	userIDs := make([]uint, 0, len(shares))
	for _, v := range shares {
		userIDs = append(userIDs, v.UserID)
	}

	var userList []User
	DB.Where("id in (?) and nick like ?", userIDs, "%"+key+"%").Find(&userList)

	for _, v := range userList {
		for i := 0; i < len(shares); i++ {
			if shares[i].UserID == v.ID {
				shares[i].User = v
			}
		}

	}
	return shares, nil
}

// GetShareByHashID 根据HashID查找分享
func GetTeamsFolderByHashID(hashID string) *TeamsFolderMember {
	id, err := hashid.DecodeHashID(hashID, hashid.ShareID)

	util.Log().Warning("hash解密, %s%s", hashID, id)
	if err != nil {
		return nil
	}
	var share TeamsFolderMember
	result := DB.First(&share, id)
	if result.Error != nil {
		return nil
	}

	return &share
}

// IsAvailable 返回此分享是否可用（是否过期）
func (share *TeamsFolderMember) IsAvailable() bool {
	if share.RemainDownloads == 0 {
		return false
	}
	if share.Expires != nil && time.Now().After(*share.Expires) {
		return false
	}

	// 检查创建者状态
	if share.Creator().Status != Active {
		return false
	}

	// 检查源对象是否存在
	var sourceID uint
	if share.IsDir {
		folder := share.SourceFolder()
		sourceID = folder.ID
	} else {
		file := share.SourceFile()
		sourceID = file.ID
	}
	if sourceID == 0 {
		// TODO 是否要在这里删除这个无效分享？
		return false
	}

	return true
}

// Creator 获取分享的创建者
func (share *TeamsFolderMember) Creator() *User {
	if share.User.ID == 0 {
		share.User, _ = GetUserByID(share.UserID)
	}
	return &share.User
}

// Source 返回源对象
func (share *TeamsFolderMember) Source() interface{} {
	if share.IsDir {
		return share.SourceFolder()
	}
	return share.SourceFile()
}

// SourceFolder 获取源目录
func (share *TeamsFolderMember) SourceFolder() *Folder {
	if share.Folder.ID == 0 {
		folders, _ := GetFoldersByIDs([]uint{share.SourceID}, share.UserID)
		if len(folders) > 0 {
			share.Folder = folders[0]
		}
	}
	return &share.Folder
}

// Source 返回源对象

// SourceFile 获取源文件
func (share *TeamsFolderMember) SourceFile() *File {
	if share.File.ID == 0 {
		files, _ := GetFilesByIDs([]uint{share.SourceID}, share.UserID)
		if len(files) > 0 {
			share.File = files[0]
		}
	}
	return &share.File
}

// CanBeDownloadBy 返回此分享是否可以被给定用户下载
func (share *TeamsFolderMember) CanBeDownloadBy(user *User) error {
	// 用户组权限
	if !user.Group.OptionsSerialized.ShareDownload {
		if user.IsAnonymous() {
			return errors.New("未登录用户无法下载")
		}
		return errors.New("您当前的用户组无权下载")
	}

	// 需要积分但未登录
	if share.Score > 0 && user.IsAnonymous() {
		return errors.New("未登录用户无法下载")
	}

	return nil
}

// WasDownloadedBy 返回分享是否已被用户下载过
func (share *TeamsFolderMember) WasDownloadedBy(user *User, c *gin.Context) (exist bool) {
	if user.IsAnonymous() {
		exist = util.GetSession(c, fmt.Sprintf("share_%d_%d", share.ID, user.ID)) != nil
	} else {
		_, exist = cache.Get(fmt.Sprintf("share_%d_%d", share.ID, user.ID))
	}

	return exist
}

// DownloadBy 增加下载次数、检查积分等，匿名用户不会缓存
func (share *TeamsFolderMember) DownloadBy(user *User, c *gin.Context) error {
	if !share.WasDownloadedBy(user, c) {
		if err := share.Purchase(user); err != nil {
			return err
		}
		share.Downloaded()
		if !user.IsAnonymous() {
			cache.Set(fmt.Sprintf("share_%d_%d", share.ID, user.ID), true,
				GetIntSetting("share_download_session_timeout", 2073600))
		} else {
			util.SetSession(c, map[string]interface{}{fmt.Sprintf("share_%d_%d", share.ID, user.ID): true})
		}
	}
	return nil
}

// Purchase 使用积分购买分享
func (share *TeamsFolderMember) Purchase(user *User) error {
	// 不需要付积分
	if share.Score == 0 || user.Group.OptionsSerialized.ShareFree || user.ID == share.UserID {
		return nil
	}

	ok := user.PayScore(share.Score)
	if !ok {
		return errors.New("积分不足")
	}

	scoreRate := GetIntSetting("share_score_rate", 100)
	gainedScore := int(math.Ceil(float64(share.Score*scoreRate) / 100))
	share.Creator().AddScore(gainedScore)

	return nil
}

// Viewed 增加访问次数
func (share *TeamsFolderMember) Viewed() {
	share.Views++
	DB.Model(share).UpdateColumn("views", gorm.Expr("views + ?", 1))
}

// Downloaded 增加下载次数
func (share *TeamsFolderMember) Downloaded() {
	share.Downloads++
	if share.RemainDownloads > 0 {
		share.RemainDownloads--
	}
	DB.Model(share).Updates(map[string]interface{}{
		"downloads":        share.Downloads,
		"remain_downloads": share.RemainDownloads,
	})
}

// Update 更新分享属性
func (share *TeamsFolderMember) Update(props map[string]interface{}) error {
	return DB.Model(share).Updates(props).Error
}

// Delete 删除分享
func (share *TeamsFolderMember) Delete() error {
	return DB.Model(share).Delete(share).Error
}

// DeleteShareBySourceIDs 根据原始资源类型和ID删除文件
func DeleteTeamsFoloderBySourceIDs(sources []uint, isDir bool) error {
	return DB.Where("source_id in (?) and is_dir = ?", sources, isDir).Delete(&TeamsFolderMember{}).Error
}
func TransferTeamsFoldersToUsers(dirs []uint, folderIteams []FolderItem, UserItems []TeamsFolderMember) (err error) {
	DB.Where("source_id in (?)", dirs).Delete(&TeamsFolderMember{})
	for i := 0; i < len(UserItems); i++ {
		for j := 0; j < len(folderIteams); j++ {
			UserItems[i].SourceID = folderIteams[j].Dir
			UserItems[i].SourceName = folderIteams[j].Folder.Name
			UserItems[i].IsDir = true
			UserItems[i] = GetFolderMemberPermissionByGroupRole(UserItems[i])
			var sourceMembers []TeamsFolderMember
			UserItems[i].IsRoot = UserTeamsFolderIsRoot(sourceMembers, UserItems[i])
			DB.Model(TeamsFolderMember{}).Create(&UserItems[i])
		}
	}

	return nil
}

func UserTeamsFolderIsRoot(sourceMembers []TeamsFolderMember, sourceFolder TeamsFolderMember) (IsRoot bool) {
	// 最多5000层
	var sourceId = sourceFolder.SourceID
	var userId = sourceFolder.UserID
	for i := 0; i < 5000; i++ {
		folder := GetChildFolderById(sourceId)
		if folder.ID == 0 {
			break
		}
		var member TeamsFolderMember
		DB.Model(TeamsFolderMember{}).Where("source_id = ? and user_id = ? and is_root = 1 ", folder.ID, userId).First(&member)
		if member.ID > 0 {
			//修改当前IsRoot
			DB.Model(TeamsFolderMember{}).Where("id = ?", member.ID).UpdateColumn("is_root", 0)
			return true
		} else {
			member.SourceID = folder.ID
			member.SourceName = folder.Name
			member.IsDir = true
			member.UserID = userId
			member.GroupRole = sourceFolder.GroupRole
			member = GetFolderMemberPermissionByGroupRole(member)
			member.IsRoot = false
			DB.Model(TeamsFolderMember{}).Create(&member)
			sourceId = folder.ID
		}
	}
	for i := 0; i < 5000; i++ {
		folder := GetFolderById(sourceId)
		if folder.ID == 0 {
			break
		}
		var member TeamsFolderMember
		DB.Model(TeamsFolderMember{}).Where("source_id = ? and user_id = ? and is_root = 1 ", folder.ParentID, userId).First(&member)
		if member.ID > 0 {
			return false
		} else {
			if folder.ParentID != nil {
				sourceId = *folder.ParentID
			} else {
				break
			}

		}
	}
	return true
}
func CopyTeamsMemberToFolderId(folder Folder, parentTeamsMembers []TeamsFolderMember) {
	for i := 0; i < len(parentTeamsMembers); i++ {
		parentTeamsMembers[i].ID = 0
		parentTeamsMembers[i].SourceID = folder.ID
		parentTeamsMembers[i].SourceName = folder.Name
		var sourceMembers []TeamsFolderMember
		parentTeamsMembers[i].IsRoot = UserTeamsFolderIsRoot(sourceMembers, parentTeamsMembers[i])
		DB.Model(TeamsFolderMember{}).Create(&parentTeamsMembers[i])
	}
	return
}
func GetUserFolderMember(user_id uint, source_id uint) (member TeamsFolderMember) {
	DB.Where("source_id = ? and user_id = ?", source_id, user_id).First(&member)
	return member
}
func GetTeamsFolderMembers(source_id uint) (members []TeamsFolderMember) {
	DB.Where("source_id = ? ", source_id).Find(&members)
	return members
}
func GetFolderMemberPermissionByGroupRole(UserItem TeamsFolderMember) TeamsFolderMember {

	if UserItem.GroupRole == 1 { //创建人
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = true
		UserItem.DownloadEnabled = true
		UserItem.PreviewEnabled = true
		UserItem.EditEnabled = true
		UserItem.ManaEnabled = true
	} else if UserItem.GroupRole == 2 { //可管理
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = true
		UserItem.DownloadEnabled = true
		UserItem.PreviewEnabled = true
		UserItem.EditEnabled = true
		UserItem.ManaEnabled = true
	} else if UserItem.GroupRole == 3 { //可编辑
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = true
		UserItem.DownloadEnabled = true
		UserItem.PreviewEnabled = true
		UserItem.EditEnabled = true
		UserItem.ManaEnabled = false
	} else if UserItem.GroupRole == 4 { //可上传、下载
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = true
		UserItem.DownloadEnabled = true
		UserItem.PreviewEnabled = true
		UserItem.EditEnabled = false
		UserItem.ManaEnabled = false
	} else if UserItem.GroupRole == 5 { // 仅下载
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = false
		UserItem.DownloadEnabled = true
		UserItem.PreviewEnabled = true
		UserItem.EditEnabled = false
		UserItem.ManaEnabled = false
	} else if UserItem.GroupRole == 6 { // 仅上传
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = true
		UserItem.DownloadEnabled = false
		UserItem.PreviewEnabled = false
		UserItem.EditEnabled = false
		UserItem.ManaEnabled = false
	} else if UserItem.GroupRole == 7 { //仅预览
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = false
		UserItem.DownloadEnabled = false
		UserItem.PreviewEnabled = true
		UserItem.EditEnabled = false
		UserItem.ManaEnabled = false
	} else {
		UserItem.RemainDownloads = -1
		UserItem.UploadEnabled = false
		UserItem.DownloadEnabled = false
		UserItem.PreviewEnabled = false
		UserItem.EditEnabled = false
		UserItem.ManaEnabled = false
	}
	return UserItem
}

// ListShares 列出UID下的分享
func ListTeamsFolders(uid uint, page, pageSize int, order string, publicOnly bool) ([]TeamsFolderMember, int) {
	var (
		shares []TeamsFolderMember
		total  int64
	)
	dbChain := DB
	dbChain = dbChain.Where("user_id = ?", uid)
	if publicOnly {
		dbChain = dbChain.Where("password = ?", "")
	}

	// 计算总数用于分页
	dbChain.Model(&Share{}).Count(&total)

	// 查询记录
	dbChain.Limit(pageSize).Offset((page - 1) * pageSize).Order(order).Find(&shares)
	return shares, int(total)
}

// SearchShares 根据关键字搜索分享
func SearchTeamsFolders(page, pageSize int, order, keywords string) ([]TeamsFolderMember, int) {
	var (
		shares []TeamsFolderMember
		total  int64
	)

	keywordList := strings.Split(keywords, " ")
	availableList := make([]string, 0, len(keywordList))
	for i := 0; i < len(keywordList); i++ {
		if len(keywordList[i]) > 0 {
			availableList = append(availableList, keywordList[i])
		}
	}
	if len(availableList) == 0 {
		return shares, 0
	}

	dbChain := DB
	dbChain = dbChain.Where("password = ? and remain_downloads <> 0 and (expires is NULL or expires > ?) and source_name like ?", "", time.Now(), "%"+strings.Join(availableList, "%")+"%")

	// 计算总数用于分页
	dbChain.Model(&TeamsFolderMember{}).Count(&total)

	// 查询记录
	dbChain.Limit(pageSize).Offset((page - 1) * pageSize).Order(order).Find(&shares)
	return shares, int(total)
}
